﻿// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// 
// Copyright (c) 2012, Dr. Masroor Ehsan
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//    * Neither the name of the <organization> nor the
//      names of its contributors may be used to endorse or promote products
//      derived from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 
// $Id: OrderableTestEditForm.cs 12 2012-01-27 06:11:46Z masroore@gmail.com $
// 
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using LWObjects;
using Xceed.Grid;

namespace LWEditor
{
    public partial class OrderableTestEditForm : Form
    {
        public OrderableTestEditForm()
        {
            InitializeComponent();

            foreach (var groupName in TestPrefixGroupMap.Instance.Values.OrderBy(x => x))
            {
                cbxTestGroup.Items.Add(groupName);
                cbxAccessionType.Items.Add(groupName);
            }

            foreach (var item in BillableItemsCatalog.Instance.Values.OrderBy(x => x.Code))
            {
                cbxBillableItems.Items.Add(item.Name);
            }

            foreach (var code in ResultCodeCatalog.Instance.Values.OrderBy(x => x.Name))
            {
                cbxResultCodes.Items.Add(code);
            }
        }

        public OrderableTest CurrentTest { get; private set; }

        public void InitControlsWithTestData(OrderableTest test)
        {
            CurrentTest = (OrderableTest) test.Clone();

            txtTestId.Text = CurrentTest.TestId;
            txtTestName.Text = CurrentTest.Name;
            cbxTestGroup.SelectedIndex = cbxTestGroup.Items.IndexOf(CurrentTest.Lab);
            cbxAccessionType.SelectedIndex = !string.IsNullOrEmpty(CurrentTest.AccessionType)
                                                 ? cbxAccessionType.Items.IndexOf(CurrentTest.AccessionType)
                                                 : cbxTestGroup.SelectedIndex;
            txtListPrice.Text = CurrentTest.ListPrice;
            chkAutoFinalize.Checked = CurrentTest.AutoFinalizeTest;
            chkBillable.Checked = CurrentTest.Billable;
            chkIsProfile.Checked = CurrentTest.IsProfile;
            chkNotOrderable.Checked = CurrentTest.NotOrderable;
            chkAutoSelComp.Checked = CurrentTest.AutoSelectProfileComponents;
            chkAllCompsReturn.Checked = CurrentTest.AllComponentsReturnForProfile;
            txtMnemonics.Lines = CurrentTest.Mnemonics.ToArray();

            cboReportSequence.Items.Clear();
            if (!string.IsNullOrEmpty(test.Lab))
            {
                var sequences = (from t in OrderableTestCatalog.Instance.GetTestsInLab(test.Lab)
                                 orderby t.ReportSequence
                                 select t.ReportSequence).Distinct();
                cboReportSequence.Items.AddRange(sequences.ToArray());
            }
            cboReportSequence.Text = test.ReportSequence;

            if (CurrentTest.ActiveDate > DateTime.MinValue)
            {
                chkSetActiveDate.Checked = true;
                dteActiveDate.Value = CurrentTest.ActiveDate;
            }

            if (CurrentTest.InactiveDate > DateTime.MinValue)
            {
                chkSetActiveDate.Checked = true;
                dteInactiveDate.Value = CurrentTest.InactiveDate;
            }

            chkSetActiveDate_CheckedChanged(null, null);

            switch (test.ProfilePrinting)
            {
                case ProfilePrintingType.Components:
                    rbPrintComponents.Checked = true;
                    break;
                case ProfilePrintingType.Profile:
                    rbPrintProfile.Checked = true;
                    break;
                default:
                    rbPrintNone.Checked = true;
                    break;
            }

            LoadProfileComponentsCombo(CurrentTest.Lab, CurrentTest.TestId);
            PopulateResultCodesGrid();
            PopulateBillableItemsGrid();
            PopulateProfileComponentsGrid();
            chkIsProfile_CheckedChanged(this, null);
        }

        private void LoadProfileComponentsCombo(string lab, string testId)
        {
            IEnumerable<OrderableTest> tests;
            if (!string.IsNullOrEmpty(lab))
            {
                if (!string.IsNullOrEmpty(testId))
                {
                    tests = from t in OrderableTestCatalog.Instance.GetTestsInLab(lab)
                            where t.TestId != testId
                            select t;
                }
                else
                {
                    tests = from t in OrderableTestCatalog.Instance.GetTestsInLab(lab)
                            select t;
                }
            }
            else
            {
                tests = string.IsNullOrEmpty(testId)
                            ? OrderableTestCatalog.Instance.Values
                            : OrderableTestCatalog.Instance.Values.Where(t => t.TestId != testId);
            }

            foreach (var test in tests)
            {
                cboProfileComponent.Items.Add(test);
            }
        }

        private void PopulateResultCodesGrid(int selIndex = -1)
        {
            grdResultCodes.BeginInit();
            DataRow rowSelected = null;
            try
            {
                grdResultCodes.DataRows.Clear();
                var curIndex = 0;
                if (CurrentTest.ResultCodes.Count > 0)
                {
                    foreach (var resCode in CurrentTest.ResultCodes)
                    {
                        var row = grdResultCodes.DataRows.AddNew();
                        row.Cells["Name"].Value = resCode.Result.Name;
                        row.Cells["Code"].Value = resCode.Result.Code;
                        row.Cells["RefRange"].Value = resCode.Result.ReferenceRange;
                        row.Cells["Units"].Value = resCode.Result.Units;
                        row.Cells["Units"].Value = resCode.Result.Units;
                        row.Cells["MajSort"].Value = resCode.Result.MajorSort;
                        row.Cells["MinSort"].Value = resCode.Result.MinorSort;
                        row.Tag = resCode;

                        if (selIndex == curIndex++)
                        {
                            row.CanBeSelected = true;
                            row.CanBeCurrent = true;
                            rowSelected = row;
                        }

                        row.EndEdit();
                    }
                }
            }
            finally
            {
                grdResultCodes.EndInit();
            }

            if (rowSelected != null)
            {
                grdResultCodes.Focus();
                grdResultCodes.SelectedRows.Clear();
                grdResultCodes.SelectedRows.Add(rowSelected);
                grdResultCodes.CurrentRow = rowSelected;

                grdResultCodes_SelectedRowsChanged(null, null);
            }
        }

        public void InitNewTestWithGroup(string groupName)
        {
            CurrentTest = new OrderableTest();
            var index = cbxTestGroup.Items.IndexOf(groupName);
            if (index != -1)
            {
                cbxTestGroup.SelectedIndex = index;
                var prefix = TestPrefixGroupMap.Instance.GetPrefixFromGroup(groupName);
                var lastNum = OrderableTestCatalog.Instance.GetLastTestNumForPrefix(prefix);
                txtTestId.Text = string.Format(@"{0}{1:000}", prefix, lastNum + 1);
            }

            LoadProfileComponentsCombo(groupName, string.Empty);
            rbPrintNone.Checked = true;
            chkBillable.Checked = true;
            chkIsProfile_CheckedChanged(this, null);
        }

        private void PopulateBillableItemsGrid()
        {
            grdBillableItems.BeginInit();
            try
            {
                grdBillableItems.DataRows.Clear();
                CurrentTest.BillableItems.ForEach(x =>
                                                      {
                                                          var row = grdBillableItems.DataRows.AddNew();
                                                          row.Cells["Name"].Value = x.Name;
                                                          row.Cells["Code"].Value = x.Code;
                                                          row.Cells["Price"].Value = x.Price;
                                                          row.Tag = x;
                                                          row.EndEdit();
                                                      });
            }
            finally
            {
                grdBillableItems.EndInit();
            }
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            CurrentTest.TestId = txtTestId.Text.Trim().ToUpper();
            if (string.IsNullOrEmpty(CurrentTest.TestId))
            {
                MessageBox.Show(@"Test Code cannot be null!");
                return;
            }

            CurrentTest.Name = txtTestName.Text.Trim();
            if (string.IsNullOrEmpty(CurrentTest.Name))
            {
                MessageBox.Show(@"Test Name cannot be null!");
                return;
            }

            if (cbxTestGroup.SelectedIndex == -1)
            {
                MessageBox.Show(@"Lab/Group cannot be null!");
                return;
            }
            CurrentTest.Lab = cbxTestGroup.SelectedItem.ToString();

            int nVal;
            int.TryParse(txtListPrice.Text.Trim(), out nVal);
            CurrentTest.ListPrice = nVal.ToString(CultureInfo.InvariantCulture);

            var accType = cbxAccessionType.Text.Trim();
            CurrentTest.AccessionType = !string.IsNullOrEmpty(accType) ? accType : CurrentTest.Lab;
            CurrentTest.IsProfile = chkIsProfile.Checked;
            CurrentTest.Billable = chkBillable.Checked;
            CurrentTest.NotOrderable = chkNotOrderable.Checked;
            CurrentTest.AutoFinalizeTest = chkAutoFinalize.Checked;
            CurrentTest.AutoSelectProfileComponents = chkAutoSelComp.Checked;
            CurrentTest.AllComponentsReturnForProfile = chkAllCompsReturn.Checked;

            var seq = cboReportSequence.Text.Trim();
            CurrentTest.ReportSequence = !string.IsNullOrEmpty(seq)
                                             ? int.Parse(seq).ToString(CultureInfo.InvariantCulture)
                                             : string.Empty;

            if (chkSetActiveDate.Checked)
            {
                CurrentTest.ActiveDate = dteActiveDate.Value;
                CurrentTest.InactiveDate = dteInactiveDate.Value;
            }

            CurrentTest.ProfilePrinting = ProfilePrintingType.None;
            if (CurrentTest.IsProfile)
            {
                if (rbPrintComponents.Checked)
                {
                    CurrentTest.ProfilePrinting = ProfilePrintingType.Components;
                }
                else if (rbPrintProfile.Checked)
                {
                    CurrentTest.ProfilePrinting = ProfilePrintingType.Profile;
                }
            }

            CurrentTest.Mnemonics.Clear();
            foreach (var line in txtMnemonics.Lines)
            {
                var data = line.Trim();
                if (!string.IsNullOrEmpty(data))
                    CurrentTest.Mnemonics.Add(data);
            }

            CurrentTest.Components.ReindexSortSequences();
            DialogResult = DialogResult.OK;
        }

        private void btnAutoGenTestId_Click(object sender, EventArgs e)
        {
            var testId = txtTestId.Text.Trim();
            if (string.IsNullOrEmpty(testId) && (cbxTestGroup.SelectedIndex != -1))
            {
                var groupName = (string) cbxTestGroup.SelectedItem;
                var prefix = TestPrefixGroupMap.Instance.GetPrefixFromGroup(groupName);
                var lastNum = OrderableTestCatalog.Instance.GetLastTestNumForPrefix(prefix);
                testId = string.Format("{0}{1:0000}", prefix, lastNum + 1);
                txtTestId.Text = testId;
            }
        }

        private void btnAutoGenResultCode_Click(object sender, EventArgs e)
        {
            var resCode = txtResultCode.Text.Trim();
            if (String.IsNullOrEmpty(resCode))
            {
                var lastNum = ResultCodeCatalog.Instance.GetLastNum();
                resCode = string.Format(@"RC{0:0000}", lastNum + 1);
                txtResultCode.Text = resCode;
            }
        }

        private void btnAddBillableItem_Click(object sender, EventArgs e)
        {
            if (cbxBillableItems.SelectedIndex != -1)
            {
                var name = (string) cbxBillableItems.Items[cbxBillableItems.SelectedIndex];
                var item = BillableItemsCatalog.Instance.FindItemByName(name);
                if (CurrentTest.BillableItems.FindIndex(x => string.Compare(x.Code, item.Code, true) == 0) != -1)
                {
                    MessageBox.Show(@"Duplicate items not allowed!");
                    return;
                }

                CurrentTest.BillableItems.Add(item);
                PopulateBillableItemsGrid();
            }
        }

        private void btnDeleteBillableItem_Click(object sender, EventArgs e)
        {
            if (grdBillableItems.CurrentRow != null)
            {
                try
                {
                    var code = ((BillableItem) grdBillableItems.CurrentRow.Tag).Code;
                    var item = BillableItemsCatalog.Instance.FindItemById(code);
                    CurrentTest.BillableItems.Remove(item);
                    PopulateBillableItemsGrid();
                }
                catch (Exception)
                {
                }
            }
        }

        private void btnDeleteResultCode_Click(object sender, EventArgs e)
        {
            if (grdResultCodes.CurrentRow != null)
            {
                var link = (TestResultCodeLink) grdResultCodes.CurrentRow.Tag;
                if (MessageBox.Show(@"Really delete?", @"Confirm", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    CurrentTest.ResultCodes.Remove(link);
                    PopulateResultCodesGrid();
                }
            }
        }

        private void btnNewResultCode_Click(object sender, EventArgs e)
        {
            var lastNum = ResultCodeCatalog.Instance.GetLastNum();
            txtResultCode.Text = string.Format("RC{0:0000}", lastNum + 1);
            txtResultName.Text = string.Empty;
            txtReferenceRange.Text = string.Empty;
            txtResultUnits.Text = string.Empty;
            txtResultMajSort.Text = string.Empty;
            txtResultMinSort.Text = string.Empty;
        }

        private void btnAddResultCode_Click(object sender, EventArgs e)
        {
            if (!ValidateResultEdits())
                return;

            var txtCode = txtResultCode.Text.Trim().ToUpper();

            if (CurrentTest.ResultCodes.Exists(txtCode))
            {
                MessageBox.Show(@"Duplicate Result Codes are not allowed in the same test!");
                return;
            }

            if (ResultCodeCatalog.Instance.ContainsKey(txtCode))
            {
                MessageBox.Show(@"Test Catalog already contains this Result Code!");
                return;
            }

            var txtName = txtResultName.Text;
            var code = new ResultCode
                           {
                               Code = txtCode,
                               Name = txtName,
                               ReferenceRange = txtReferenceRange.Text,
                               Units = txtResultUnits.Text.Trim(),
                               MajorSort = txtResultMajSort.Text.Trim(),
                               MinorSort = txtResultMinSort.Text.Trim()
                           };

            var link = new TestResultCodeLink {Result = code};
            CurrentTest.ResultCodes.Add(link);
            ResultCodeCatalog.Instance.Add(code.Code, code);
            PopulateResultCodesGrid(CurrentTest.ResultCodes.Count - 1);
        }

        private bool ValidateResultEdits()
        {
            if (string.IsNullOrEmpty(txtResultCode.Text.Trim().ToUpper()))
            {
                MessageBox.Show(@"Result Code cannot be blank");
                return false;
            }

            if (string.IsNullOrEmpty(txtResultName.Text.Trim()))
            {
                MessageBox.Show(@"Result Name cannot be empty");
                return false;
            }

            return true;
        }

        private void OrderableTestEditForm_KeyUp(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Escape:
                    DialogResult = DialogResult.Cancel;
                    break;
                case Keys.F5:
                    btnOk_Click(this, null);
                    break;
            }
        }

        private void btnPascalCase_Click(object sender, EventArgs e)
        {
            var text = txtTestName.Text.Trim();
            txtTestName.Text = Utils.ConvertToPascalCase(text);
        }

        private void btnUpperCase_Click(object sender, EventArgs e)
        {
            var text = txtTestName.Text.Trim();
            txtTestName.Text = text.ToUpper();
        }

        private void btnLowerCase_Click(object sender, EventArgs e)
        {
            var text = txtTestName.Text.Trim();
            txtTestName.Text = text.ToLower();
        }

        private void chkIsProfile_CheckedChanged(object sender, EventArgs e)
        {
            grpProfilePrinting.Enabled = chkIsProfile.Checked;
            tabProfileComponents.Enabled = chkIsProfile.Checked;
            tabControl1.Refresh();
        }

        private void btnComponentAdd_Click(object sender, EventArgs e)
        {
            if (cboProfileComponent.SelectedIndex != -1)
            {
                var test = (OrderableTest) cboProfileComponent.Items[cboProfileComponent.SelectedIndex];


                if (CurrentTest.Components.FindIndex(x => string.Compare(x.Test.TestId, test.TestId, true) == 0) != -1)
                {
                    MessageBox.Show(@"Duplicate items not allowed!");
                    return;
                }

                var comp = new ProfileComponent {Test = test};
                CurrentTest.Components.Add(comp);
                PopulateProfileComponentsGrid();
                cboProfileComponent.SelectedIndex = -1;
            }
        }

        private void PopulateProfileComponentsGrid()
        {
            grdProfileComponents.BeginInit();
            try
            {
                grdProfileComponents.DataRows.Clear();
                CurrentTest.Components.ForEach(x =>
                                                   {
                                                       var row = grdProfileComponents.DataRows.AddNew();
                                                       row.Cells["Code"].Value = x.Test.TestId;
                                                       row.Cells["Name"].Value = x.Test.Name;
                                                       row.Cells["Accession"].Value = x.Test.AccessionType;
                                                       row.Tag = x;
                                                       row.EndEdit();
                                                   });
            }
            finally
            {
                grdProfileComponents.EndInit();
            }
        }

        private void btnComponentRemove_Click(object sender, EventArgs e)
        {
            if (grdProfileComponents.CurrentRow != null)
            {
                var comp = (ProfileComponent) grdProfileComponents.CurrentRow.Tag;
                if (MessageBox.Show(@"Really delete?", @"Confirm", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    CurrentTest.Components.Remove(comp);
                    PopulateProfileComponentsGrid();
                    cboProfileComponent.SelectedIndex = -1;
                }
            }
        }

        private void OrderableTestEditForm_Load(object sender, EventArgs e)
        {
            txtTestId.Focus();
        }

        private void tabResultCodes_Click(object sender, EventArgs e)
        {
            txtResultCode.Focus();
        }

        private void btnSaveResultCode_Click(object sender, EventArgs e)
        {
            if (!ValidateResultEdits()) return;
            var txtCode = txtResultCode.Text.Trim().ToUpper();
            var txtName = txtResultName.Text;

            var code = ResultCodeCatalog.Instance.GetResultObjectFromCode(txtCode);
            code.Code = txtCode;
            code.Name = txtName;
            code.ReferenceRange = txtReferenceRange.Text;
            code.Units = txtResultUnits.Text.Trim();
            code.MajorSort = txtResultMajSort.Text.Trim();
            code.MinorSort = txtResultMinSort.Text.Trim();

            PopulateResultCodesGrid();
        }

        private void btnAddExistingResultCode_Click(object sender, EventArgs e)
        {
            if (cbxResultCodes.SelectedIndex == -1) return;

            var code = (ResultCode) cbxResultCodes.Items[cbxResultCodes.SelectedIndex];
            var link = new TestResultCodeLink {Result = code};
            CurrentTest.ResultCodes.Add(link);
            PopulateResultCodesGrid(CurrentTest.ResultCodes.Count - 1);
        }

        private void btnResultCodeUp_Click(object sender, EventArgs e)
        {
            if (grdResultCodes.CurrentRow != null)
            {
                var link = (TestResultCodeLink) grdResultCodes.CurrentRow.Tag;
                var index = CurrentTest.ResultCodes.MoveUp(link);
                PopulateResultCodesGrid(index);
            }
        }

        private void btnResultCodeDown_Click(object sender, EventArgs e)
        {
            if (grdResultCodes.CurrentRow != null)
            {
                var link = (TestResultCodeLink) grdResultCodes.CurrentRow.Tag;
                var index = CurrentTest.ResultCodes.MoveDown(link);
                PopulateResultCodesGrid(index);
            }
        }

        private void grdResultCodes_SelectedRowsChanged(object sender, EventArgs e)
        {
            if (grdResultCodes.CurrentRow != null)
            {
                var link = (TestResultCodeLink) grdResultCodes.CurrentRow.Tag;
                if (link.Result != null)
                {
                    txtResultCode.Text = link.Result.Code;
                    txtResultName.Text = link.Result.Name;
                    txtReferenceRange.Text = link.Result.ReferenceRange;
                    txtResultUnits.Text = link.Result.Units;
                    txtResultMajSort.Text = link.Result.MajorSort;
                    txtResultMinSort.Text = link.Result.MinorSort;
                }
            }
        }

        private void grdBillableItems_SelectedRowsChanged(object sender, EventArgs e)
        {
            if (grdBillableItems.CurrentRow != null)
            {
                try
                {
                    var code = ((BillableItem) grdBillableItems.CurrentRow.Tag).Code;
                    var item = BillableItemsCatalog.Instance.FindItemById(code);
                    cbxBillableItems.SelectedIndex = cbxBillableItems.Items.IndexOf(item.Name);
                }
                catch
                {
                }
            }
        }

        private string FindSequence(bool findLowest)
        {
            if (cbxTestGroup.SelectedIndex == -1)
                return string.Empty;

            var lab = cbxTestGroup.SelectedItem.ToString();
            if (findLowest)
            {
                return (from t in OrderableTestCatalog.Instance.GetTestsInLab(lab)
                        where !string.IsNullOrEmpty(t.ReportSequence)
                        orderby t.ReportSequence
                        select t.ReportSequence).FirstOrDefault();
            }

            return (from t in OrderableTestCatalog.Instance.GetTestsInLab(lab)
                    where !string.IsNullOrEmpty(t.ReportSequence)
                    orderby t.ReportSequence descending
                    select t.ReportSequence).FirstOrDefault();
        }

        private void btnFindLowestSeq_Click(object sender, EventArgs e)
        {
            cboReportSequence.Text = FindSequence(true);
        }

        private void btnFindHighestSeq_Click(object sender, EventArgs e)
        {
            cboReportSequence.Text = FindSequence(false);
        }

        private void chkSetActiveDate_CheckedChanged(object sender, EventArgs e)
        {
            dteActiveDate.Enabled = chkSetActiveDate.Checked;
            dteInactiveDate.Enabled = chkSetActiveDate.Checked;
        }
    }
}